<script>
import TabNav from './tab-nav'

export default {
  name: 'ElTabs',

  components: {
    TabNav
  },

  props: {
    type: String,
    activeName: String,
    closable: Boolean,
    addable: Boolean,
    // eslint-disable-next-line vue/require-prop-types
    value: {},
    editable: Boolean,
    tabPosition: {
      type: String,
      default: 'top'
    },
    beforeLeave: Function,
    stretch: Boolean
  },

  provide() {
    return {
      rootTabs: this
    }
  },

  data() {
    return {
      currentName: this.value || this.activeName,
      panes: []
    }
  },

  watch: {
    activeName(value) {
      this.setCurrentName(value)
    },
    value(value) {
      this.setCurrentName(value)
    },
    currentName(value) {
      if (this.$refs.nav) {
        this.$nextTick(() => {
          this.$refs.nav.$nextTick((_) => {
            this.$refs.nav.scrollToActiveTab()
          })
        })
      }
    }
  },

  created() {
    if (!this.currentName) {
      this.setCurrentName('0')
    }

    this.$on('tab-nav-update', this.calcPaneInstances.bind(null, true))
  },

  mounted() {
    this.calcPaneInstances()
  },

  updated() {
    this.calcPaneInstances()
  },

  methods: {
    calcPaneInstances(isForceUpdate = false) {
      if (this.$slots.default) {
        const paneSlots = this.$slots.default.filter(
          (vnode) =>
            vnode.tag &&
            vnode.componentOptions &&
            vnode.componentOptions.Ctor.options.name === 'ElTabPane'
        )
        // update indeed
        const panes = paneSlots.map(({ componentInstance }) => componentInstance)
        const panesChanged = !(
          panes.length === this.panes.length &&
          panes.every((pane, index) => pane === this.panes[index])
        )
        if (isForceUpdate || panesChanged) {
          this.panes = panes
        }
      } else if (this.panes.length !== 0) {
        this.panes = []
      }
    },
    handleTabClick(tab, tabName, event) {
      if (tab.disabled) return
      this.setCurrentName(tabName)
      this.$emit('tab-click', tab, event)
    },
    handleTabRemove(pane, ev) {
      if (pane.disabled) return
      ev.stopPropagation()
      this.$emit('edit', pane.name, 'remove')
      this.$emit('tab-remove', pane.name)
    },
    handleTabAdd() {
      this.$emit('edit', null, 'add')
      this.$emit('tab-add')
    },
    setCurrentName(value) {
      const changeCurrentName = () => {
        this.currentName = value
        this.$emit('input', value)
      }
      if (this.currentName !== value && this.beforeLeave) {
        const before = this.beforeLeave(value, this.currentName)
        if (before && before.then) {
          before.then(
            () => {
              changeCurrentName()
              this.$refs.nav && this.$refs.nav.removeFocus()
            },
            () => {
              // https://github.com/ElemeFE/element/pull/14816
              // ignore promise rejection in `before-leave` hook
            }
          )
        } else if (before !== false) {
          changeCurrentName()
        }
      } else {
        changeCurrentName()
      }
    }
  },

  render(h) {
    const {
      type,
      handleTabClick,
      handleTabRemove,
      handleTabAdd,
      currentName,
      panes,
      editable,
      addable,
      tabPosition,
      stretch
    } = this

    const newButton =
      editable || addable ? (
        <span
          class='el-tabs__new-tab'
          on-click={handleTabAdd}
          tabindex='0'
          on-keydown={(ev) => {
            if (ev.keyCode === 13) {
              handleTabAdd()
            }
          }}>
          <i class='el-icon-plus'></i>
        </span>
      ) : null

    const navData = {
      props: {
        currentName,
        onTabClick: handleTabClick,
        onTabRemove: handleTabRemove,
        editable,
        type,
        panes,
        stretch
      },
      ref: 'nav'
    }
    const header = (
      <div class={['el-tabs__header', `is-${tabPosition}`]}>
        {newButton}
        <tab-nav {...navData}></tab-nav>
      </div>
    )
    const panels = <div class='el-tabs__content'>{this.$slots.default}</div>

    return (
      <div
        class={{
          'el-tabs': true,
          'el-tabs--card': type === 'card',
          [`el-tabs--${tabPosition}`]: true,
          'el-tabs--border-card': type === 'border-card'
        }}>
        {tabPosition !== 'bottom' ? [header, panels] : [panels, header]}
      </div>
    )
  }
}
</script>
